from enum import Enum
from .MatcherBase import MatcherBase


class MicroFF_STATE(Enum):
    NONE = 0
    HEAD_FF = 1
    HEAD_RECV = 2
    TAIL_FF = 3


class FFMatcher(MatcherBase):
    """
    FF协议说明

    1.以0xff 0x01为包头
    2.以0xff 0x02为包尾
    3.数据段中的0xff转义为0xff 0x00

    例:
        传输{0x41 0xff 0x42}

        转为MicroFF协议后:

        0xff 0x01 0x41 0xff 0x00 0x42 0xff 0x02

        -------------------------------------------------

        解包:
        去掉包头包尾
        0x41 0xff 0x00 0x42

        将数据中的 0xff 0x00 转为 0xff (遇到0xff,即忽略下一字节,因为现在数据中只有0xff 0x00一种组合)
        0x41 0xff 0x42
    """

    def __init__(this, matchCallback=None):
        super().__init__(matchCallback)
        this.ff_state = MicroFF_STATE.NONE
        this.Reset()

    def InStream(this, data: bytes):
        # py的data是数组
        for b in data:
            # 未匹配到包头
            if this.ff_state == MicroFF_STATE.NONE:
                this.Reset()
                if b == 0xFF:
                    # 包头也写入流
                    this.stream.write(b)
                    # 匹配到包头0xff
                    this.ff_state = MicroFF_STATE.HEAD_FF

            # 匹配到包头0xff
            elif this.ff_state == MicroFF_STATE.HEAD_FF:
                if b == 0x01:
                    # 包头也写入流
                    this.stream.write(b)
                    # 匹配到包头0x01
                    this.ff_state = MicroFF_STATE.HEAD_RECV
                # 不匹配，重置
                else:
                    this.ff_state = MicroFF_STATE.NONE

            # 接收状态(匹配到包头0x01后进入,或者遇到0xff 0x00后返回到接收状态)
            elif this.ff_state == MicroFF_STATE.HEAD_RECV:
                # 写入流,所有数据写入流
                this.stream.write(b)

                # 匹配到“可能的”包尾0(下一个可能是0x00)
                if b == 0xFF:
                    this.ff_state = MicroFF_STATE.TAIL_FF

            # 匹配到包尾0xff
            elif this.ff_state == MicroFF_STATE.TAIL_FF:
                # 收到0x02,已完成
                if b == 0x02:
                    # 写入流
                    this.stream.write(b)
                    # 引发事件
                    this.invokeCallback()

                    # 重置状态机
                    this.ff_state = MicroFF_STATE.NONE
                else:
                    # 不是0x02，返回数据接收状态
                    # 由于MicroFF协议中,在这一步只可能匹配到0x02或者0x00
                    # 这里不将0x00写入流,自动完成0xff 0x00的转换
                    this.ff_state = MicroFF_STATE.HEAD_RECV

    def Reset(this):
        """重置"""
        this.ff_state = MicroFF_STATE.NONE
        super().Reset()

    def EncodeData(this, data: bytes):
        """将data转换为微型FF协议数据格式,包括包头包尾"""
        pkg = bytearray()
        pkg.extend(bytes([0xFF, 0x01]))  # 包头

        for b in data:
            pkg.append(b)
            # 如果为0xff,转为0xff 0x00
            if b == 0xFF:
                pkg.append(0)

        pkg.extend(bytes([0xFF, 0x02]))  # 包尾
        return bytes(pkg)

    # 内部实现
    def invokeCallback(this):
        buf = this.stream.get()
        this.InvokeMatchCallback(buf[2:-2])  # 去掉包头包尾
        
